package frpc.manager.hash;

import frpc.manager.basics.RedisBasicsBusinessManager;
import frpc.manager.lock.IRedisLockManager;
import frpc.manager.operation.GiveCacheData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.HashOperations;

import java.math.BigDecimal;
import java.util.Map;

/**
 * 类描述:  Redis——Hash对象处理实现
 *
 * @author 王雷
 * @version 1.0.0
 * @date 2022/6/2 0002 下午 3:12
 */
@Slf4j
@SuppressWarnings("unchecked")
public class RedisHashManagerImpl extends RedisBasicsBusinessManager implements IRedisHashManager {

    /**
     * 功能描述：Redis基础处理对象
     *
     * @param iRedisLockManager Redis——锁处理接口
     * @author : 王雷
     * @date : 2020/11/26 0026 下午 4:48
     */
    protected RedisHashManagerImpl(IRedisLockManager iRedisLockManager) {
        super(iRedisLockManager);
    }

    /**
     * 功能描述：获取Hash处理对象完成自定义处理
     *
     * @author : 王雷
     * @date : 2022/6/2 0002 下午 3:12
     */
    @Override
    public <T> HashOperations<String, String, T> giveHashOperations() {
        return giveRedisTemplate().opsForHash();
    }

    /**
     * 功能描述：添加数据到指定的Key中
     *
     * @param key   需要插入的Key
     * @param value 需要插入的内容
     * @param time  失效时间，单位：秒
     * @author : 王雷
     * @date : 2022/6/2 0002 下午 3:12
     */
    @Override
    public <T> void addValueByKey(String key, Map<String, T> value, long time) {
        giveHashOperations().putAll(key, value);
        if (time > 0L) {
            expire(key, time);
        }
    }

    /**
     * 功能描述：添加数据到指定的Key中
     *
     * @param key      需要插入的Key
     * @param valueKey 需要插入的键
     * @param value    需要插入的内容
     * @param time     失效时间，单位：秒
     * @author : 王雷
     * @date : 2022/6/2 0002 下午 3:12
     */
    @Override
    public <T> void addValueByKey(String key, String valueKey, T value, long time) {
        giveHashOperations().put(key, valueKey, value);
        if (time > 0L) {
            expire(key, time);
        }
    }

    /**
     * 功能描述：添加数据到指定的Key中，不限制时间
     *
     * @param key   需要插入的Key
     * @param value 需要插入的内容
     * @author : 王雷
     * @date : 2022/6/2 0002 下午 3:12
     */
    @Override
    public <T> void addValueByKey(String key, Map<String, T> value) {
        addValueByKey(key, value, 0L);
    }

    /**
     * 功能描述：添加数据到指定的Key中
     *
     * @param key      需要插入的Key
     * @param valueKey 需要插入的键
     * @param value    需要插入的内容
     * @author : 王雷
     * @date : 2022/6/2 0002 下午 3:12
     */
    @Override
    public <T> void addValueByKey(String key, String valueKey, T value) {
        addValueByKey(key, valueKey, value, 0L);
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    @Override
    public <T> void hdel(String key, T... item) {
        giveHashOperations().delete(key, (Object) item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    @Override
    public boolean hHasKey(String key, String item) {
        return giveHashOperations().hasKey(key, item);
    }

    /**
     * 根据存储Key及MapKey获取对应的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    @Override
    public <T> T hget(String key, String item) {
        return (T) giveHashOperations().get(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几
     */
    @Override
    public Double hincrToDouble(String key, String item, BigDecimal by) {
        return giveHashOperations().increment(key, item, Math.abs(by.doubleValue()));
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几
     */
    @Override
    public Long hincrToInteger(String key, String item, long by) {
        return giveHashOperations().increment(key, item, Math.abs(by));
    }

    /**
     * hash长度
     *
     * @param key 键
     * @return 长度
     */
    @Override
    public Long hdecrSize(String key) {
        return giveHashOperations().size(key);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少的数量
     */
    @Override
    public Double hdecrToDouble(String key, String item, BigDecimal by) {
        return giveHashOperations().increment(key, item, (Math.abs(by.multiply(new BigDecimal("-1")).doubleValue())));
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少的数量
     */
    @Override
    public Long hdecrToInteger(String key, String item, long by) {
        return giveHashOperations().increment(key, item, (Math.abs(by) * -1));
    }

    /**
     * 获取数据
     *
     * @param key 键
     * @return 值
     */
    @Override
    public <T> Map<String, T> giveValueByKey(String key) {
        return (Map<String, T>) giveHashOperations().entries(key);
    }

//    /**
//     * 属性描述：访问空值Key前缀
//     *
//     * @date : 2020/11/30 0030 下午 6:20
//     */
//    protected static final String HASH_VISIT_NULL_LOCK_PREFIX = "Hash_Visit_Null_Lock_Prefix_";

    /**
     * 属性描述：业务处理锁前缀
     *
     * @date : 2020/11/30 0030 下午 6:20
     */
    protected static final String HASH_MANAGER_NULL_LOCK_PREFIX = "Hash_Manager_Null_Lock_Prefix_";

    /**
     * 获取数据，带锁处理
     *
     * @param key           键
     * @param giveCacheData 数据无效时的回调函数
     * @return 值
     */
    @Override
    public <T> Map<String, T> giveValueByKeyToLock(String key, GiveCacheData<Map<String, T>> giveCacheData) throws Exception {
        return giveValueByKeyToLock(key, giveCacheData, null);
    }

    /**
     * 获取数据，带锁处理
     *
     * @param key           键
     * @param giveCacheData 数据无效时的回调函数
     * @return 值
     */
    @Override
    public <T> Map<String, T> giveValueByKeyToLock(String key, GiveCacheData<Map<String, T>> giveCacheData, Long putMaxTime) throws Exception {
        /*
         * 第一步：检查访问缓存对象中是否有数据
         * 访问缓存中的数据是在没有获取到值或者逻辑处理出现异常的时候才会存在；
         * 存在的时间为1分钟；
         * */
        if (!super.hasKey(key)) {
            return iRedisLockManager.autoLockToManager(HASH_MANAGER_NULL_LOCK_PREFIX + key, 0, redisTemplate -> {
                //再次验证值是否存在
                if (super.hasKey(key)) {
                    return giveValueByKey(key);
                } else {
                    final Map<String, T> stringObjectMap = giveCacheData.giveManager();
                    if (stringObjectMap != null && !stringObjectMap.isEmpty()) {
                        //将数据装入缓存中，默认保存的时间为60秒
                        addValueByKey(key, stringObjectMap, (putMaxTime == null || putMaxTime <= 0L) ? 60L : putMaxTime);
                    }
                    return stringObjectMap;
                }
            });
        }
        return giveValueByKey(key);
    }
}
